package com.spsoft.vatoutinv.jobHandler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.spsoft.core.constants.CommonConstants;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BusinessException;
import com.spsoft.core.model.Result;
import com.spsoft.core.model.leqidmz.param.UploadInvoiceParams;
import com.spsoft.core.model.leqidmz.param.UploadInvoiceParamsBdcxs;
import com.spsoft.core.model.leqidmz.param.UploadInvoiceParamsBdczl;
import com.spsoft.core.model.leqidmz.param.UploadInvoiceParamsLkys;
import com.spsoft.core.model.leqidmz.response.UploadInvoiceVO;
import com.spsoft.core.utils.BeanUtils;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.einvoicetodmz.service.DmzApiClientService;
import com.spsoft.vatoutinv.constants.CommonConstant;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.*;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.enums.TdysEnum;
import com.spsoft.vatoutinv.service.vmsfulloutinvoice.*;
import com.spsoft.vms.redis.service.impl.QueryUploadInvoiceVmsQueueServiceImpl;
import com.spsoft.vms.redis.service.impl.UploadInvoiceVmsQueueServiceImpl;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数电票上传定时任务
 *
 * @author : chenxudong
 * @date : 2024/3/13 10:12
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class VmsUploadInvoiceJob {

    public static final String LOG_MSG = "(数电票上传定时任务)";

    private final DmzApiClientService dmzApiClientService;

    private final UploadInvoiceVmsQueueServiceImpl uploadInvoiceVmsQueue;

    private final QueryUploadInvoiceVmsQueueServiceImpl queryUploadInvoiceVmsQueue;

    private final VmsFullOutInvoiceDetailsService invoiceDetailsService;

    private final VmsFullOutInvoiceItemsService invoiceItemsService;

    private final VmsFullOutInvoiceItemsExpService invoiceItemsExpService;

    private final VmsFullOutInvoiceItemsAddService invoiceItemsAddService;

    private final VmsFullOutInvoiceTdywService invoiceTdywService;

    private final VmsFullOutInvoiceTdywItemService invoiceTdywItemService;

    private final VmsFullOutInvoiceCekcService invoiceCekcService;

    /**
     * 乐企数电票上传方式 1：定时任务单张上传 2：定时任务批量上传
     */
    @Value("${leqi.upload.method}")
    private int uploadMethod;

    /**
     * 定时任务单张上传，每次获取队列数据数量
     */
    @Value("${leqi.upload.method.single.size}")
    private int singleSize;

    /**
     * 定时任务批量上传，每次获取队列数据数量
     */
    @Value("${leqi.upload.method.batch.size}")
    private int batchSize;

    @XxlJob("vmsUploadInvoiceJobHandler")
    public ReturnT<String> vmsUploadInvoiceJobHandler() {
        // 分片参数
        int shardIndex = XxlJobHelper.getShardIndex();
        int shardTotal = XxlJobHelper.getShardTotal();
        XxlJobHelper.log("{}分片参数，当前分片序号：{}, 总分片数：{}", LOG_MSG, shardIndex, shardTotal);

        // 该定时任务使用分片广播模式，防止多个执行器同时执行造成redis队列压力过大，根据当前分片序号进行睡眠
        try {
            long time = (shardIndex + 1) * 500L;
            Thread.sleep(time);
            XxlJobHelper.log("{}分片序号：{}，睡眠{}ms完成", LOG_MSG, shardIndex, time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long start = System.currentTimeMillis();
        XxlJobHelper.log("{}开始执行", LOG_MSG);

        // 根据乐企数电票上传方式，区分获取队列数据数量
        int count;
        if (uploadMethod == 1) {
            count = singleSize;
        } else if (uploadMethod == 2) {
            count = batchSize;
        } else {
            XxlJobHelper.log("{}乐企数电票上传方式错误：{}", LOG_MSG, uploadMethod);
            XxlJobHelper.handleFail();
            return ReturnT.FAIL;
        }

        // 自定义队列获取数量
        if (StringUtils.isNotBlank(XxlJobHelper.getJobParam())) {
            count = Integer.parseInt(XxlJobHelper.getJobParam());
        }

        // 获取数电票上传队列中的待上传发票主键id
        List<Long> idList = uploadInvoiceVmsQueue.getMessagesFromQueue(count);
        boolean success = true;
        if (CollectionUtil.isNotEmpty(idList)) {
            // 待上传发票id去重
            Set<Long> idSet = new HashSet<>(idList);
            XxlJobHelper.log("{}本次获取数电票上传队列中的待上传发票数量：{}", LOG_MSG, idSet.size());
            LambdaQueryWrapper<VmsFullOutInvoiceDetails> query = new LambdaQueryWrapper<>();
            query.in(VmsFullOutInvoiceDetails::getFoidid, idSet);
            List<VmsFullOutInvoiceDetails> invoiceDetailList = invoiceDetailsService.list(query);
            // 数电票上传逻辑
            success = uploadInvoice(invoiceDetailList);
        }

        long end = System.currentTimeMillis();
        XxlJobHelper.log("{}执行完成，用时：{}ms", LOG_MSG, end - start);
        if (success) {
            return ReturnT.SUCCESS;
        } else {
            XxlJobHelper.handleFail();
            return ReturnT.FAIL;
        }
    }

    /**
     * 数电票上传逻辑实现
     * @param invoiceDetailList 发票主信息List
     */
    public boolean uploadInvoice(List<VmsFullOutInvoiceDetails> invoiceDetailList) {
        // 根据机构编码进行分组上传
        Map<String, List<VmsFullOutInvoiceDetails>> collect = invoiceDetailList.stream().collect(
                Collectors.groupingBy(VmsFullOutInvoiceDetails::getQydjid));

        // 单个机构上传异常不影响其他机构上传
        boolean success = true;
        for (Map.Entry<String, List<VmsFullOutInvoiceDetails>> entry : collect.entrySet()) {
            XxlJobHelper.log("{}机构编码：{}，待上传发票数量：{}", LOG_MSG, entry.getKey(), entry.getValue().size());
            // 同一机构的不同特定要素发票进行分组
            List<VmsFullOutInvoiceDetails> tdysList = entry.getValue().stream().peek(VmsFullOutInvoiceDetails -> {
                if (StringUtils.isBlank(VmsFullOutInvoiceDetails.getTdys())) {
                    VmsFullOutInvoiceDetails.setTdys("");
                }
            }).collect(Collectors.toList());
            Map<String, List<VmsFullOutInvoiceDetails>> tdysCollect = tdysList.stream().collect(
                    Collectors.groupingBy(VmsFullOutInvoiceDetails::getTdys));
            for (Map.Entry<String, List<VmsFullOutInvoiceDetails>> tdysEntry : tdysCollect.entrySet()) {
                XxlJobHelper.log("{}机构编码：{}，其中特定要素：{}，发票数量：{}",
                        LOG_MSG, entry.getKey(), TdysEnum.getNameByCode(tdysEntry.getKey()), tdysEntry.getValue().size());
                try {
                    if (uploadMethod == 1) {
                        for (VmsFullOutInvoiceDetails invoiceDetail : tdysEntry.getValue()) {
                            // 构造单张上传参数
                            UploadInvoiceParams uploadParam = buildUploadParamSingle(tdysEntry.getKey(), Collections.singletonList(invoiceDetail));
                            // 定时任务单张上传
                            XxlJobHelper.log("{}定时任务单张上传", LOG_MSG);
                            boolean isSuccess = dmzUploadInvoice(Collections.singletonList(uploadParam), Collections.singletonList(invoiceDetail),
                                    tdysEntry.getKey(), entry.getKey());
                            if (!isSuccess) {
                                success = false;
                            }
                        }
                    } else if (uploadMethod == 2) {
                        // 构造批量上传参数
                        List<UploadInvoiceParams> uploadParamList = buildUploadParamList(tdysEntry);
                        // 定时任务批量上传
                        XxlJobHelper.log("{}定时任务批量上传", LOG_MSG);
                        boolean isSuccess = dmzUploadInvoice(uploadParamList, tdysEntry.getValue(), tdysEntry.getKey(), entry.getKey());
                        if (!isSuccess) {
                            success = false;
                        }
                    }
                } catch (BusinessException e) {
                    XxlJobHelper.log("{}机构编码：{}，数电票上传失败：{}",
                            LOG_MSG, entry.getKey(), e.getMsg());
                    // 更新发票的上传状态、上传流水号、上传结果
                    for (VmsFullOutInvoiceDetails invoiceDetail : tdysEntry.getValue()) {
                        LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey())
                                .set(VmsFullOutInvoiceDetails::getScjg, e.getMsg())
                                .eq(VmsFullOutInvoiceDetails::getFoidid, invoiceDetail.getFoidid());
                        invoiceDetailsService.update(updateWrapper);
                    }
                    success = false;
                } catch (Exception e) {
                    XxlJobHelper.log("{}机构编码：{}，数电票上传失败：{}",
                            LOG_MSG, entry.getKey(), e);
                    // 更新发票的上传状态、上传流水号、上传结果
                    for (VmsFullOutInvoiceDetails invoiceDetail : tdysEntry.getValue()) {
                        LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                        updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey())
                                .set(VmsFullOutInvoiceDetails::getScjg, StringUtils.isBlank(e.getMessage()) ? "数电票上传定时任务发生异常" : e.getMessage())
                                .eq(VmsFullOutInvoiceDetails::getFoidid, invoiceDetail.getFoidid());
                        invoiceDetailsService.update(updateWrapper);
                    }
                    success = false;
                }
            }
        }
        return success;
    }

    /**
     * 调用DMZ完成数电票上传
     * @param uploadParamList 组装后的上传发票参数
     * @param invoiceDetailList 上传的本地发票主信息
     * @param tdys 特定要素
     * @param deptCode 机构编码
     * @return
     */
    private boolean dmzUploadInvoice(List<UploadInvoiceParams> uploadParamList, List<VmsFullOutInvoiceDetails> invoiceDetailList, String tdys, String deptCode) {
        boolean success = true;
        // 只有未上传的发票会进行上传操作，如果数据不是未上传，构建上传参数会跳过，此处参数为空直接返回成功
        if (CollectionUtil.isEmpty(uploadParamList)) {
            return true;
        }
        // 调用数电票上传接口
        Result<UploadInvoiceVO> result = dmzApiClientService.uploadInvoice(uploadParamList, tdys);
        if (ResponseEnum.SUCCESS.getCode().equals(result.getCode())) {
            UploadInvoiceVO resultData = result.getData();
            XxlJobHelper.log("{}机构编码：{}，特定要素：{}，数电票上传成功，出参：{}",
                    LOG_MSG, deptCode, TdysEnum.getNameByCode(tdys), JSONObject.toJSONString(result));
            // 更新发票的上传状态、上传流水号、上传结果
            for (VmsFullOutInvoiceDetails invoiceDetail : invoiceDetailList) {
                LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_1.getKey())
                        .set(VmsFullOutInvoiceDetails::getScjg, "等待定时任务查询上传结果中")
                        .set(VmsFullOutInvoiceDetails::getSllsh, resultData.getSllsh())
                        .eq(VmsFullOutInvoiceDetails::getFoidid, invoiceDetail.getFoidid());
                invoiceDetailsService.update(updateWrapper);
            }
            // 将受理流水号放入查询上传发票结果延时队列，后续定时任务进行查询上传发票结果操作
            String message = resultData.getSllsh() + "-" + deptCode + "-" + "0";
            boolean flag = queryUploadInvoiceVmsQueue.addMessageToQueue(message);
            if (flag) {
                XxlJobHelper.log("{}放入查询上传发票结果延时队列成功，受理流水号：{}",
                        LOG_MSG, resultData.getSllsh());
            } else {
                XxlJobHelper.log("{}放入查询上传发票结果延时队列失败，受理流水号：{}",
                        LOG_MSG, resultData.getSllsh());
            }
        } else if (ResponseEnum.LEQI_TIMEOUT_ERROR.getCode().equals(result.getCode())) {
            // 调用乐企平台出现网络异常
            XxlJobHelper.log("{}机构编码：{}，特定要素：{}，调用乐企平台出现网络异常，出参：{}",
                    LOG_MSG, deptCode, TdysEnum.getNameByCode(tdys), JSONObject.toJSONString(result));
            // 更新发票的上传状态为未上传，等待后续定时任务重新上传
            for (VmsFullOutInvoiceDetails invoiceDetail : invoiceDetailList) {
                // 取出上传结果，用于判断本次网络异常是否重新放队列进行重新上传操作
                String scjg;
                int retryCount = 1;
                if (StringUtils.isNotBlank(invoiceDetail.getScjg())
                        && invoiceDetail.getScjg().contains(ResponseEnum.LEQI_TIMEOUT_ERROR.getMsg())) {
                    // 取出重试次数，上传结果格式：调用乐企平台出现网络异常，重试次数：3
                    int count = Integer.parseInt(invoiceDetail.getScjg().substring(invoiceDetail.getScjg().length() - 1));
                    retryCount = count + 1;
                    scjg = ResponseEnum.LEQI_TIMEOUT_ERROR.getMsg() + "，重试次数：" + retryCount;
                } else {
                    scjg = ResponseEnum.LEQI_TIMEOUT_ERROR.getMsg() + "，重试次数：1";
                }
                LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                if (retryCount < 3) {
                    updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_0.getKey());
                } else {
                    updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey());
                }
                updateWrapper.set(VmsFullOutInvoiceDetails::getScjg, scjg);
                updateWrapper.eq(VmsFullOutInvoiceDetails::getFoidid, invoiceDetail.getFoidid());
                invoiceDetailsService.update(updateWrapper);
                if (retryCount < 3) {
                    // 将发票主键id放入数电票上传队列，等待后续定时任务重新上传
                    boolean flag = uploadInvoiceVmsQueue.addMessageToQueue(invoiceDetail.getFoidid());
                    if (flag) {
                        XxlJobHelper.log("{}重新放入数电票上传队列成功，发票号码：{}",
                                LOG_MSG, invoiceDetail.getFphm());
                    } else {
                        XxlJobHelper.log("{}重新放入数电票上传队列失败，发票号码：{}",
                                LOG_MSG, invoiceDetail.getFphm());
                    }
                }
            }
            success = false;
        } else {
            XxlJobHelper.log("{}机构编码：{}，特定要素：{}，数电票上传失败：{}",
                    LOG_MSG, deptCode, TdysEnum.getNameByCode(tdys), result.getMessage());
            // 更新发票的上传状态、上传流水号、上传结果
            for (VmsFullOutInvoiceDetails invoiceDetail : invoiceDetailList) {
                LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey())
                        .set(VmsFullOutInvoiceDetails::getScjg, result.getMessage())
                        .eq(VmsFullOutInvoiceDetails::getFoidid, invoiceDetail.getFoidid());
                invoiceDetailsService.update(updateWrapper);
            }
            success = false;
        }
        return success;
    }

    /**
     * 构造单张发票上传参数信息
     * @param tdys 特定要素
     * @param invoiceDetailList 单张发票信息List
     */
    private UploadInvoiceParams buildUploadParamSingle(String tdys, List<VmsFullOutInvoiceDetails> invoiceDetailList) {
        UploadInvoiceParams uploadParam = new UploadInvoiceParams();

        if (StringUtils.isBlank(tdys) || TdysEnum.TDYS_00.getCode().equals(tdys)) {
            // 无特定要素
            List<UploadInvoiceParams> paramList = buildUploadParam(invoiceDetailList);
            if (CollectionUtil.isNotEmpty(paramList)) {
                uploadParam = paramList.get(0);
            }
        } else if (TdysEnum.TDYS_05.getCode().equals(tdys)) {
            // 不动产销售
            List<UploadInvoiceParamsBdcxs> bdcxsParamList = buildUploadParamBdcxs(invoiceDetailList);
            if (CollectionUtil.isNotEmpty(bdcxsParamList)) {
                uploadParam = bdcxsParamList.get(0);
            }
        } else if (TdysEnum.TDYS_06.getCode().equals(tdys)) {
            // 不动产租赁
            List<UploadInvoiceParamsBdczl> bdczlParamList = buildUploadParamBdczl(invoiceDetailList);
            if (CollectionUtil.isNotEmpty(bdczlParamList)) {
                uploadParam = bdczlParamList.get(0);
            }
        } else if (TdysEnum.TDYS_09.getCode().equals(tdys)) {
            // 旅客运输
            List<UploadInvoiceParamsLkys> lkysParamList = buildUploadParamLkys(invoiceDetailList);
            if (CollectionUtil.isNotEmpty(lkysParamList)) {
                uploadParam = lkysParamList.get(0);
            }
        } else {
            throw new BusinessException(ResponseEnum.TDYS_NOT_SUPPORT);
        }

        return uploadParam;
    }

    /**
     * 构造发票上传参数信息
     * @param tdysEntry 根据特定要素分组的发票数据
     */
    private List<UploadInvoiceParams> buildUploadParamList(Map.Entry<String, List<VmsFullOutInvoiceDetails>> tdysEntry) {
        List<UploadInvoiceParams> uploadParamList = new ArrayList<>();

        if (StringUtils.isBlank(tdysEntry.getKey()) || TdysEnum.TDYS_00.getCode().equals(tdysEntry.getKey())) {
            // 无特定要素
            List<UploadInvoiceParams> paramList = buildUploadParam(tdysEntry.getValue());
            uploadParamList.addAll(paramList);
        } else if (TdysEnum.TDYS_05.getCode().equals(tdysEntry.getKey())) {
            // 不动产销售
            List<UploadInvoiceParamsBdcxs> bdcxsParamList = buildUploadParamBdcxs(tdysEntry.getValue());
            uploadParamList.addAll(bdcxsParamList);
        } else if (TdysEnum.TDYS_06.getCode().equals(tdysEntry.getKey())) {
            // 不动产租赁
            List<UploadInvoiceParamsBdczl> bdczlParamList = buildUploadParamBdczl(tdysEntry.getValue());
            uploadParamList.addAll(bdczlParamList);
        } else if (TdysEnum.TDYS_09.getCode().equals(tdysEntry.getKey())) {
            // 旅客运输
            List<UploadInvoiceParamsLkys> lkysParamList = buildUploadParamLkys(tdysEntry.getValue());
            uploadParamList.addAll(lkysParamList);
        } else {
            throw new BusinessException(ResponseEnum.TDYS_NOT_SUPPORT);
        }

        return uploadParamList;
    }

    /**
     * 构造非特定要素数电发票上传参数
     * @param invoiceDetailList 发票信息
     */
    public List<UploadInvoiceParams> buildUploadParam(List<VmsFullOutInvoiceDetails> invoiceDetailList) {
        List<UploadInvoiceParams> paramsList = new ArrayList<>();
        for (VmsFullOutInvoiceDetails invoiceDetail : invoiceDetailList) {
            // 上传状态不为：未上传，不做处理
            if (!CommonEnum.INVOICE_UPLOAD_STATUS_0.getKey().equals(invoiceDetail.getSczt())) {
                continue;
            }
            // 构造发票上传参数
            UploadInvoiceParams uploadParam = buildCommonUploadParam(invoiceDetail, UploadInvoiceParams.class);
            paramsList.add(uploadParam);
        }
        return paramsList;
    }

    /**
     * 构造不动产销售特定要素数电发票上传参数
     * @param invoiceDetailList 发票信息
     */
    public List<UploadInvoiceParamsBdcxs> buildUploadParamBdcxs(List<VmsFullOutInvoiceDetails> invoiceDetailList) {
        List<UploadInvoiceParamsBdcxs> paramsList = new ArrayList<>();
        for (VmsFullOutInvoiceDetails invoiceDetail : invoiceDetailList) {
            // 上传状态不为：未上传，不做处理
            if (!CommonEnum.INVOICE_UPLOAD_STATUS_0.getKey().equals(invoiceDetail.getSczt())) {
                continue;
            }
            // 构造发票上传参数
            UploadInvoiceParamsBdcxs bdcxsParam = buildCommonUploadParam(invoiceDetail, UploadInvoiceParamsBdcxs.class);

            // 获取发票特定业务信息
            List<VmsFullOutInvoiceTdyw> invoiceTdywList = invoiceTdywService.getInfoByFoidid(invoiceDetail.getFoidid());
            // 填充特定业务信息
            if (ObjectUtil.isNotEmpty(invoiceTdywList)) {
                VmsFullOutInvoiceTdyw invoiceTdyw = invoiceTdywList.get(0);
                UploadInvoiceParamsBdcxs.Bdcxstdys bdcxsTdys = new UploadInvoiceParamsBdcxs.Bdcxstdys();
                BeanUtils.copyProperties(invoiceTdyw, bdcxsTdys);
                bdcxsTdys.setXh(1);
                bdcxsParam.setBdcxstdys(Collections.singletonList(bdcxsTdys));
                if (CommonConstant.STR_Y.equals(invoiceTdyw.getDfgtgmbz())) {
                    List<VmsFullOutInvoiceTdywItem> tdywItemList = invoiceTdywItemService.getInvoiceTdywItemByTdywId(invoiceTdyw.getTdywId());
                    List<UploadInvoiceParamsBdcxs.GtgmfInfo> gtgmfInfoList = BeanUtils.copyListProperties(tdywItemList, UploadInvoiceParamsBdcxs.GtgmfInfo::new);
                    bdcxsParam.setGtgmfList(gtgmfInfoList);
                }
            } else {
                throw new BusinessException(ResponseEnum.TDYW_NOT_FIND_EXCEPTION);
            }

            paramsList.add(bdcxsParam);
        }
        return paramsList;
    }

    /**
     * 构造不动产租赁特定要素数电发票上传参数
     * @param invoiceDetailList 发票信息
     */
    public List<UploadInvoiceParamsBdczl> buildUploadParamBdczl(List<VmsFullOutInvoiceDetails> invoiceDetailList) {
        List<UploadInvoiceParamsBdczl> paramsList = new ArrayList<>();
        for (VmsFullOutInvoiceDetails invoiceDetail : invoiceDetailList) {
            // 上传状态不为：未上传，不做处理
            if (!CommonEnum.INVOICE_UPLOAD_STATUS_0.getKey().equals(invoiceDetail.getSczt())) {
                continue;
            }
            // 构造发票上传参数
            UploadInvoiceParamsBdczl bdczlParam = buildCommonUploadParam(invoiceDetail, UploadInvoiceParamsBdczl.class);

            // 获取发票特定业务信息
            List<VmsFullOutInvoiceTdyw> invoiceTdywList = invoiceTdywService.getInfoByFoidid(invoiceDetail.getFoidid());
            // 填充特定业务信息
            if (ObjectUtil.isNotEmpty(invoiceTdywList)) {
                VmsFullOutInvoiceTdyw invoiceTdyw = invoiceTdywList.get(0);
                BeanUtils.copyProperties(invoiceTdyw, bdczlParam);
            } else {
                throw new BusinessException(ResponseEnum.TDYW_NOT_FIND_EXCEPTION);
            }

            paramsList.add(bdczlParam);
        }
        return paramsList;
    }

    /**
     * 构造旅客运输特定要素数电发票上传参数
     * @param invoiceDetailList 发票信息
     */
    public List<UploadInvoiceParamsLkys> buildUploadParamLkys(List<VmsFullOutInvoiceDetails> invoiceDetailList) {
        List<UploadInvoiceParamsLkys> paramsList = new ArrayList<>();
        for (VmsFullOutInvoiceDetails invoiceDetail : invoiceDetailList) {
            // 上传状态不为：未上传，不做处理
            if (!CommonEnum.INVOICE_UPLOAD_STATUS_0.getKey().equals(invoiceDetail.getSczt())) {
                continue;
            }
            // 构造发票上传参数
            UploadInvoiceParamsLkys lkysParam = buildCommonUploadParam(invoiceDetail, UploadInvoiceParamsLkys.class);

            // 获取发票特定业务信息
            List<VmsFullOutInvoiceTdyw> invoiceTdywList = invoiceTdywService.getInfoByFoidid(invoiceDetail.getFoidid());
            // 填充特定业务信息
            if (ObjectUtil.isNotEmpty(invoiceTdywList)) {
                List<UploadInvoiceParamsLkys.CxrxxInfo> cxrxxInfoList = BeanUtils.copyListProperties(invoiceTdywList, UploadInvoiceParamsLkys.CxrxxInfo::new,(s, t)->{
                    t.setCxrzjlxDm(s.getCxrzjlxdm());
                    t.setJtgjlxDm(s.getJtgjlxdm());
                });
                lkysParam.setCxrxxList(cxrxxInfoList);
            }

            paramsList.add(lkysParam);
        }
        return paramsList;
    }

    /**
     * 构造数电发票通用上传参数
     * @param invoiceDetail 发票主信息
     * @param clazz 数电发票上传参数实体类
     * @param <T> 不动产销售/租赁、旅客运输继承类
     */
    public <T extends UploadInvoiceParams> T buildCommonUploadParam(VmsFullOutInvoiceDetails invoiceDetail, Class<T> clazz) {
        try {
            T uploadParam = clazz.newInstance();
            // 获取发票明细信息
            List<VmsFullOutInvoiceItems> invoiceItemList = invoiceItemsService.queryInvoiceDetails(invoiceDetail.getFoidid());
            // 获取发票非必填信息
            VmsFullOutInvoiceItemsExp invoiceItemsExp = invoiceItemsExpService.getInvoiceExpInfoByFoidid(invoiceDetail.getFoidid());
            // 获取发票附加要素信息
            List<VmsFullOutInvoiceItemsAdd> invoiceItemsAddList = invoiceItemsAddService.getInvoiceAddInfoByFoidid(invoiceDetail.getFoidid());

            // 填充发票主信息
            BeanUtils.copyProperties(invoiceDetail, uploadParam);
            uploadParam.setKprq(DateUtil.format(invoiceDetail.getKprq(), CommonConstant.DATE_FORMAT_14));
            uploadParam.setCreateUser("定时任务");
            uploadParam.setDeptCode(invoiceDetail.getQydjid());
            uploadParam.setCezslxDm(invoiceDetail.getCezslxdm());

            // 填充发票明细信息
            if (CollectionUtil.isNotEmpty(invoiceItemList)) {
                List<UploadInvoiceParams.FpmxInfo> fpmxInfoList = new ArrayList<>();
                for (VmsFullOutInvoiceItems invoiceItem : invoiceItemList) {
                    UploadInvoiceParams.FpmxInfo fpmxInfo = new UploadInvoiceParams.FpmxInfo();
                    BeanUtils.copyProperties(invoiceItem, fpmxInfo);
                    String xmmc = invoiceItem.getXmmc();
                    // 货物或应税劳务、服务名称
                    fpmxInfo.setHwhyslwfwmc(xmmc);
                    // 从货物或应税劳务、服务名称中分离出商品简称和商品名称
                    if (xmmc.indexOf(CommonConstants.STRING_STAR) == 0) {
                        String[] split = invoiceItem.getXmmc().split("\\*");
                        if (split.length > 2) {
                            fpmxInfo.setSpfwjc(split[1]);
                            fpmxInfo.setXmmc(xmmc.replace("*" + split[1] + "*", ""));
                        }
                    }
                    // 免税、不征税、零税率特殊情况
                    if (ObjectUtil.isEmpty(invoiceItem.getSe())) {
                        invoiceItem.setSe(BigDecimal.ZERO);
                    }
                    fpmxInfo.setHsje(invoiceItem.getJe().add(invoiceItem.getSe()));
                    fpmxInfoList.add(fpmxInfo);
                }
                uploadParam.setFpmxList(fpmxInfoList);
            }

            // 填充发票非必填信息
            if (ObjectUtil.isNotEmpty(invoiceItemsExp)) {
                BeanUtils.copyProperties(invoiceItemsExp, uploadParam);
                // 购买方自然人标志特殊处理：01、02 转 Y、N
                if (CommonEnum.PERSON_FLAG_01.getKey().equals(invoiceItemsExp.getGmfzrrbz())) {
                    uploadParam.setGmfzrrbz(CommonConstant.STR_Y);
                } else {
                    uploadParam.setGmfzrrbz(CommonConstant.STR_N);
                }
                // 字段名称不一致，特殊处理
                if (StringUtil.isNotEmpty(invoiceItemsExp.getQydm())) {
                    uploadParam.setQyDm(invoiceItemsExp.getQydm());
                }
                if (StringUtil.isNotEmpty(invoiceItemsExp.getSgfplxdm())) {
                    uploadParam.setSgfplxDm(invoiceItemsExp.getSgfplxdm());
                }
                if (StringUtil.isNotEmpty(invoiceItemsExp.getCkywsyzcdm())) {
                    uploadParam.setCkywsyzcDm(invoiceItemsExp.getCkywsyzcdm());
                }
                if (StringUtil.isNotEmpty(invoiceItemsExp.getZzsjzjtdm())) {
                    uploadParam.setZzsjzjtDm(invoiceItemsExp.getZzsjzjtdm());
                }
            }

            // 填充发票附加要素信息
            if (CollectionUtil.isNotEmpty(invoiceItemsAddList)) {
                List<UploadInvoiceParams.FjysInfo> fjysInfoList = BeanUtils.copyListProperties(invoiceItemsAddList, UploadInvoiceParams.FjysInfo::new);
                uploadParam.setFjysList(fjysInfoList);
            }

            // 填充差额扣除信息
            if (CommonEnum.CEZS_02.getKey().equals(invoiceDetail.getCezslxdm())) {
                List<VmsFullOutInvoiceCekc> invoiceCekcList = invoiceCekcService.getInvoiceCekcInfoByFoidId(invoiceDetail.getFoidid());
                if (ObjectUtil.isNotEmpty(invoiceCekcList)) {
                    List<UploadInvoiceParams.CekcInfo> cekcInfoList = BeanUtils.copyListProperties(invoiceCekcList, UploadInvoiceParams.CekcInfo::new);
                    uploadParam.setCekcList(cekcInfoList);
                }
            }

            return uploadParam;
        } catch (Exception e) {
            XxlJobHelper.log("{}组装参数异常：{}", LOG_MSG, e);
            throw new BusinessException(ResponseEnum.BUILD_PARAM_EXCEPTION);
        }
    }
}
